package org.bdware.repository.handler;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.bdware.doip.core.doipMessage.DoipMessage;
import org.bdware.doip.core.doipMessage.DoipResponseCode;
import org.bdware.doip.core.model.digitalObject.DigitalObject;
import org.bdware.doip.core.model.digitalObject.DoType;
import org.bdware.doip.core.model.digitalObject.Element;
import org.bdware.doip.endpoint.doipServer.DoipServiceInfo;
import org.bdware.doip.endpoint.doipServer.RegistryHandlerBase;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ProxyHandler extends RegistryHandlerBase {
    static Logger logger = Logger.getLogger(ProxyHandler.class);
    static final String URL = "https://39.101.64.229:9003/doipservice/external/getDoEntity";

    public ProxyHandler(DoipServiceInfo info) {
        super(info);
    }

    @Override
    public DoipMessage handleSearch(DoipMessage request) {
        return handleUnknown(request);
    }

    @Override
    public DoipMessage handleHello(DoipMessage request) {
        return replyDoipServiceInfo(request);
    }

    @Override
    public DoipMessage handleListOps(DoipMessage request) {
        return replyAllOperations(request);
    }

    @Override
    public DoipMessage handleCreate(DoipMessage request) {
        return handleUnknown(request);
    }

    @Override
    public DoipMessage handleUpdate(DoipMessage request) {
        return handleUnknown(request);
    }

    @Override
    public DoipMessage handleDelete(DoipMessage request) {
        return handleUnknown(request);
    }

    @Override
    public DoipMessage handleRetrieve(DoipMessage request) {
        String result = null;
        String doID = request.header.parameters.id;
        try {
            HashMap<String,String> params = new HashMap<>();
            params.put("doi",doID);
            String response = sendHttps(params,URL);
            logger.debug("http response: " + response);
            Response resp = new Gson().fromJson(response,Response.class);
            if(resp.data.apiBody != null){
                ApiBody api = resp.data.apiBody;
                HashMap<String,String> apiParams = new HashMap<>();
                for (int i=0;i<api.parameters.size();i++) {
                    apiParams.put(api.parameters.get(i).getAsJsonObject().get("name").getAsString()
                            ,api.parameters.get(i).getAsJsonObject().get("default").getAsString());
                }
                if(api.method.equals("POST")){
                    result = sendHttps(apiParams,api.url);
                }else{
                    result = sendGet(apiParams,api.url);
                }
            }else if (resp.data.dbBody != null){
                result = sendJDBC(resp.data.dbBody);
            }else{
                return replyStringWithStatus(request, "HTTP response error: " + resp, DoipResponseCode.MoreThanOneErrors);
            }
        }catch (Exception e){
            e.printStackTrace();
            return replyStringWithStatus(request, "Server Exception: " + e.getMessage(), DoipResponseCode.MoreThanOneErrors);
        }
        DigitalObject digitalObject = new DigitalObject(doID, DoType.DO);
        Element e = new Element("content","JSON");
        e.setData(result.getBytes());
        digitalObject.addElements(e);
        return replyDO(request,digitalObject);
    }

    public String sendJDBC(DBBody dbBody) throws Exception {
        if(dbBody.type.equals("mysql")){
            Class.forName("com.mysql.jdbc.Driver");
        }else if(dbBody.type.equals("SQLServerDriver")){
            Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
        }
        Connection conn = DriverManager.getConnection(dbBody.jdbcUrl,dbBody.username,dbBody.password);
        Statement st = conn.createStatement();
        ResultSet rs = st.executeQuery("select * from " + dbBody.tableName + ";");
        ResultSetMetaData tableHeader = rs.getMetaData();

        JsonObject resJO = new JsonObject();
        JsonArray colummns = new JsonArray();
        int columnSize = tableHeader.getColumnCount();
        for(int i=0;i<tableHeader.getColumnCount();i++){
            colummns.add(tableHeader.getColumnName(i));
        }
        resJO.add("header",colummns);
        JsonArray rows = new JsonArray();
        while(rs.next()){
            JsonArray entries = new JsonArray();
            for(int i=0;i<tableHeader.getColumnCount();i++){
                entries.add(rs.getString(i));
            }
            rows.add(entries);
        }
        resJO.add("body",rows);
        return resJO.getAsString();
    }
    public String sendGet(Map<String,String> reqMap, String url) throws IOException {
        String result;
        url = url.split("\\?")[0];
//        if(!url.contains("?"))
            url = url + "?";
//        else
//            url = url+"&";
        for (String k:reqMap.keySet()) {
            url = url + k + "=" +reqMap.get(k) + "&";
        }
        logger.debug("final url: " + url);
        HttpGet get = new HttpGet(url);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpResponse response = httpClient.execute(get);
        InputStream in = response.getEntity().getContent();
        BufferedReader br = new BufferedReader(new InputStreamReader(in, "utf-8"));
        StringBuilder strber= new StringBuilder();
        String line;
        while((line = br.readLine())!=null){
            strber.append(line+'\n');
        }
        br.close();
        in.close();
        result = strber.toString();
        if(response.getStatusLine().getStatusCode()!= HttpStatus.SC_OK){
            result = "服务器异常";
        }
        return result;
    }

    public String sendHttps(Map<String, String> reqMap, String url){
        String result = "do http error";
        HttpPost httpPost = new HttpPost(url);

        try{
            SSLClient httpClient = new SSLClient();
            httpPost = new HttpPost(url);
            //设置参数
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");
            StringEntity stringEntity = new StringEntity(new Gson().toJson(reqMap));
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json");
            httpPost.setEntity(stringEntity);
            HttpResponse response = httpClient.execute(httpPost);
            if (response != null) {
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity);
                }
            }
        } catch (Exception e){
            System.out.println("请求异常");
            throw new RuntimeException(e);
        } finally{
            httpPost.abort();
        }
        return result;
    }

    static class Response{
        String code;
        String message;
        Data data;
    }
    static class Data{
        String doi;
        String name;
        String type;
        ApiBody apiBody;
        DBBody dbBody;
    }
    static class ApiBody{
        String method;
        String url;
        String contentType;
        JsonArray parameters;
    }
    static class DBBody{
        String type;
        String jdbcUrl;
        String contentType;
        String username;
        String password;
        String tableName;
    }
}
